#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> /* 使用sockaddr_in */
#include <strings.h>
#include <arpa/inet.h>
#include <functional>
#include <string>
#include <string.h>
#include <unistd.h>
#include "mypthread.hpp"
#include "Log.hpp"
#include "InterAddr.hpp"
using namespace LogModule;
using namespace MypthreadModule;

std::string sever_ip;
uint16_t sever_port = 0;
int sockfd = -1;
pthread_t id;

void Recv()
{
    while (true)
    {
        char buffer[1024];
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        ssize_t s = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);
        if (s > 0)
        {
            buffer[s] = 0;
            std::cerr << buffer << std::endl;
        }
    }
}

void Send()
{
    /* 发送一个online用于上线 */
    InterAddr Server(sever_ip, sever_port);
    const std::string online = "online";
    sendto(sockfd, online.c_str(), online.size(), 0, (const sockaddr *)&Server.GetAddr(), Server.Len());

    /* 向Server端发送消息 */
    while (true)
    {
        std::string input;
        std::getline(std::cin, input);
        int n = sendto(sockfd, input.c_str(), input.size(), 0, (const sockaddr *)&Server.GetAddr(), Server.Len());
        (void)n; // TODO
        if (input == "QUIT")
        {
            pthread_cancel(id);
            break;
        }
    }
}

/* 调用方式 ./udpclient sever_ip sever_port */
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        LOG(LogLevel::WARING) << "User: ./udpclient sever_ip sever_port";
        return -1;
    }

    sever_ip = argv[1];
    sever_port = std::stoi(argv[2]);

    // 1. 创建socket
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        std::cerr << "socket error" << std::endl;
        return 2;
    }

    /*
    创建两个线程
    1. 线程recver去时刻监听Server端的消息
    2. 线程sender去向Server端发送消息
    */
    Thread recver(Recv);
    Thread sender(Send);

    id = recver.GetTid();

    recver.Start();
    sender.Start();

    recver.Join();
    sender.Join();

    return 0;
}